题解:
题意:有一个基环树森林,每个点有权值,取出互不相邻的任意个点,问最大权值和是多少。
先考虑是一棵树的情况:
dp[i][0/1]
d
p
[
i
]
[
0
/
1
]
表示以
i
i
为根的子树中取
(1)
(
1
)
或不取
(0)
(
0
)
的最大权值和
dp[u][0]=∑max(dp[v][0],dp[v][1])
d
p
[
u
]
[
0
]
=
∑
m
a
x
(
d
p
[
v
]
[
0
]
,
d
p
[
v
]
[
1
]
)
dp[u][1]=a[u]+∑dp[v][0]
d
p
[
u
]
[
1
]
=
a
[
u
]
+
∑
d
p
[
v
]
[
0
]
那加一条边变成了环之后呢?
取出环上相邻的两个点
x
x
,,将连边断开,变成一棵树,而这两个点不能同时取。
分别以这两个点为根做树形
dp
d
p
,
ans=max(dp1[x][0],dp2[y][0])
a
n
s
=
m
a
x
(
d
p
1
[
x
]
[
0
]
,
d
p
2
[
y
]
[
0
]
)
。
Code:
C
o
d
e
:
#include<bits/stdc++.h>
#define N 2000005
#define ll long long
using namespace std;
int tot=-1,rr,rl,head[N],s[N],n,vis[N],flag;
ll f[N][2],ans,a[N];
struct node
{
int next,vet;
}edge[N];
void add(int u,int v)
{
edge[++tot].vet=v;
edge[tot].next=head[u];
head[u]=tot;
}
void dfs(int u,int fa)
{
vis[u]=true;
for(int i=head[u];i!=-1&&(!flag);i=edge[i].next)
{
int v=edge[i].vet;
if(v!=fa)
{
if(vis[v])
{
rl=u;
rr=v;
s[i]=s[i^1]=-1;
flag=true;
break;
}
dfs(v,u);
}
}
}
void dp(int u,int fa,int ban)
{
vis[u]=true;
if(u!=ban)f[u][1]=a[u];else f[u][1]=0;
f[u][0]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].vet;
if(v!=fa&&s[i]!=-1)
{
dp(v,u,ban);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%lld%d",&a[i],&x);
add(x,i);add(i,x);
}
for(int i=1;i<=n;i++)
if(!vis[i])
{
flag=false;
dfs(i,0);
ll mx=0;
dp(rl,0,rr);
mx=max(f[rl][0],f[rl][1]);
dp(rr,0,rl);
mx=max(mx,max(f[rr][0],f[rr][1]));
ans+=mx;
}
printf("%lld\n",ans);
}